<template>
  <template v-for="item in filteredMenuItems" :key="item.path">
    <!-- 包含子菜单的项目 -->
    <ElSubMenu
      v-if="hasChildren(item)"
      :index="item.path || item.meta.title"
      :level="level"
    >
      <template #title>
        <MenuItemIcon :icon="item.meta.icon" :color="theme?.iconColor" />
        <span class="menu-name">
          {{ formatMenuTitle(item.meta.title) }}
        </span>
        <div v-if="item.meta.showBadge" class="art-badge" style="right: 10px" />
      </template>

      <SidebarSubmenu
        :list="item.children"
        :is-mobile="isMobile"
        :level="level + 1"
        :theme="theme"
        @close="closeMenu"
      />
    </ElSubMenu>

    <!-- 普通菜单项 -->
    <ElMenuItem
      v-else
      :index="item.path || item.meta.title"
      :level-item="level + 1"
      @click="goPage(item)"
    >
      <MenuItemIcon :icon="item.meta.icon" :color="theme?.iconColor" />
      <div
        v-show="item.meta.showBadge && level === 0 && !menuOpen"
        class="art-badge"
        style="right: 5px"
      />

      <template #title>
        <span class="menu-name">
          {{ formatMenuTitle(item.meta.title) }}
        </span>
        <div v-if="item.meta.showBadge" class="art-badge" />
        <div
          v-if="item.meta.showTextBadge && (level > 0 || menuOpen)"
          class="art-text-badge"
        >
          {{ item.meta.showTextBadge }}
        </div>
      </template>
    </ElMenuItem>
  </template>
</template>

<script setup lang="ts">
import { computed } from "vue";
import type { AppRouteRecord } from "@/types/router";
import { formatMenuTitle } from "@/router/utils/utils";
import { handleMenuJump } from "@/utils/navigation";
import { useSettingStore } from "@/store/modules/setting";

interface MenuTheme {
  iconColor?: string;
}

interface Props {
  /** 菜单标题 */
  title?: string;
  /** 菜单列表 */
  list?: AppRouteRecord[];
  /** 主题配置 */
  theme?: MenuTheme;
  /** 是否为移动端模式 */
  isMobile?: boolean;
  /** 菜单层级 */
  level?: number;
}

interface Emits {
  /** 关闭菜单事件 */
  (e: "close"): void;
}

const props = withDefaults(defineProps<Props>(), {
  title: "",
  list: () => [],
  theme: () => ({}),
  isMobile: false,
  level: 0,
});

const emit = defineEmits<Emits>();

const settingStore = useSettingStore();

const { menuOpen } = storeToRefs(settingStore);

/**
 * 过滤后的菜单项列表
 * 只显示未隐藏的菜单项
 */
const filteredMenuItems = computed(() => filterRoutes(props.list));

/**
 * 跳转到指定页面
 * @param item 菜单项数据
 */
const goPage = (item: AppRouteRecord): void => {
  closeMenu();
  handleMenuJump(item);
};

/**
 * 关闭菜单
 * 触发父组件的关闭事件
 */
const closeMenu = (): void => {
  emit("close");
};

/**
 * 递归过滤菜单路由，移除隐藏的菜单项
 * 如果一个父菜单的所有子菜单都被隐藏，则父菜单也会被隐藏
 * @param items 菜单项数组
 * @returns 过滤后的菜单项数组
 */
const filterRoutes = (items: AppRouteRecord[]): AppRouteRecord[] => {
  return items
    .filter((item) => {
      // 如果当前项被隐藏，直接过滤掉
      if (item.meta.isHide) {
        return false;
      }

      // 如果有子菜单，递归过滤子菜单
      if (item.children && item.children.length > 0) {
        const filteredChildren = filterRoutes(item.children);
        // 如果所有子菜单都被过滤掉了，则隐藏父菜单
        return filteredChildren.length > 0;
      }

      // 叶子节点且未被隐藏，保留
      return true;
    })
    .map((item) => ({
      ...item,
      children: item.children ? filterRoutes(item.children) : undefined,
    }));
};

/**
 * 判断菜单项是否包含可见的子菜单
 * @param item 菜单项数据
 * @returns 是否包含可见的子菜单
 */
const hasChildren = (item: AppRouteRecord): boolean => {
  if (!item.children || item.children.length === 0) {
    return false;
  }
  // 递归检查是否有可见的子菜单
  const filteredChildren = filterRoutes(item.children);
  return filteredChildren.length > 0;
};
</script>

<script lang="ts">
/**
 * 菜单图标组件
 * 用于渲染菜单项的图标
 */
const MenuItemIcon = defineComponent({
  name: "MenuItemIcon",
  props: {
    /** 图标内容 */
    icon: {
      type: String,
      default: "",
    },
    /** 图标颜色 */
    color: {
      type: String,
      default: "",
    },
  },
  setup(props) {
    return () =>
      h("i", {
        class: "menu-icon iconfont-sys",
        style: props.color ? { color: props.color } : undefined,
        innerHTML: props.icon,
      });
  },
});
</script>
